package org.footito.android.data.update;

import java.util.HashSet;
import java.util.Iterator;

import org.footito.android.activity.UpdateTask;
import org.footito.android.data.Event;
import org.footito.android.data.TeamStatus;
import org.footito.android.data.database.ProviderAdapter;
import org.footito.android.tools.Constants;
import org.footito.android.tools.Log;
import org.footito.android.tools.NotificationHelper;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;

/**
 * Class for managing data loading from server in background
 * 
 * @author 15pouces
 * 
 */
public class UpdateService extends Service implements UpdateListener {

	private static final String ACTION = "startupdate";

	public static boolean bindListener(Context context, ServiceConnection conn) {
		Intent intent = new Intent(context, UpdateService.class);
		intent.setAction(ACTION);
		boolean binded = context.bindService(intent, conn, Context.BIND_AUTO_CREATE);
		return binded;
	}

	public static void startService(Context context) {
		Intent intent = new Intent(context, UpdateService.class);
		intent.setAction(ACTION);
		context.startService(intent);
	}

	public static void scheduleService(Context context, int frequencyInHour) {
		unScheduleService(context);
		long frequency = frequencyInHour * Constants.MILLISECONDS_IN_HOUR;

		long timeInMillis = System.currentTimeMillis() + frequency;

		Intent intentService = new Intent(context, BroadcastForService.class);
		PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intentService, 0);

		Log.v("prepare the clock to check the service in " + timeInMillis + " seconds, and every " + timeInMillis);
		AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
		alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, timeInMillis, frequency, pendingIntent);
	}

	public static void unScheduleService(Context context) {
		Intent intentService = new Intent(context, BroadcastForService.class);
		PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intentService, 0);
		AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
		alarmManager.cancel(pendingIntent);
	}

	private HashSet<UpdateListener> listeners = new HashSet<UpdateListener>();
	private final IBinder mBinder = new LocalBinder();
	private boolean updateRunning = false;
	private NotificationHelper notificationHelper;

	public void addUpdateListener(UpdateListener listener) {
		this.listeners.add(listener);
	}

	public void removeUpdateListener(UpdateListener listener) {
		this.listeners.remove(listener);
	}

	public void loadMoreEvents() {
		updateListenersOnComplete(null);
	}

	private void loadLastData() {
		Log.d("Start loading");
		updateRunning = true;
		new UpdateTask(this, this).execute((Void[]) null);
	}

	@Override
	public IBinder onBind(Intent intent) {
		return mBinder;
	}

	@Override
	public void onCreate() {
		Log.d("Service created");
		notificationHelper = new NotificationHelper(getApplicationContext());
		super.onCreate();
	}

	@Override
	public void onStart(Intent intent, int startId) {
		super.onStart(intent, startId);

		if (!ACTION.equals(intent.getAction()) || updateRunning) {
			Log.d("Not restarted");
			return;
		}

		Log.d("Load data");
		loadLastData();
	}

	@Override
	public void onComplete(UpdateResults results) {
		if (results.lastElement != null) {
			ProviderAdapter pa = new ProviderAdapter(this);
			Event status = pa.getEvent(results.lastElementId);
			notificationHelper.notifyNewStatus((TeamStatus) status);
		}

		updateListenersOnComplete(results);
		Log.d("Update completed");
		updateRunning = false;
	}

	@Override
	public void onError(Exception e) {
		Log.d("Error on update : " + e.getClass().getCanonicalName());
		updateListenersOnError(e);
		updateRunning = false;
	}

	@Override
	public void onProgress(Integer... progressId) {
		updateListenersOnProgress(new Integer[] { UpdateListener.COMMENTSLOADINGSTARTED });
	}

	private void updateListenersOnComplete(UpdateResults results) {
		for (Iterator<UpdateListener> iterator = listeners.iterator(); iterator.hasNext();) {
			UpdateListener listener = (UpdateListener) iterator.next();
			if (listener != null)
				listener.onComplete(results);
		}
	}

	private void updateListenersOnError(Exception e) {
		for (Iterator<UpdateListener> iterator = listeners.iterator(); iterator.hasNext();) {
			UpdateListener listener = (UpdateListener) iterator.next();
			if (listener != null)
				listener.onError(e);
		}
	}

	private void updateListenersOnProgress(Integer[] integers) {
		for (Iterator<UpdateListener> iterator = listeners.iterator(); iterator.hasNext();) {
			UpdateListener listener = (UpdateListener) iterator.next();
			if (listener != null)
				listener.onProgress(integers);
		}
	}

	public class LocalBinder extends Binder {
		public UpdateService getService() {
			return UpdateService.this;
		}
	}

}
